using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;

namespace FAssetsSeparate
{
    public static class PrefabAssetSeparate
    {
        /// <summary> 所有资产数据 </summary>
        static readonly Dictionary<string, string> _fileContentDict = new();

        /// <summary> 匹配的 guid 资产路径 </summary>
        static readonly List<string> _matchingGUIDAssetPaths = new();

        /// <summary> 分离路径 </summary>
        const string SEPARATE_PATH = "Assets/!-AssetsSeparate";
        // Separation

        /// <summary> 分离 </summary>
        /// <param name="paths">路径列表</param>
        public static void Separate(List<string> paths)
        {
            var complete = true;

            if (Directory.Exists(SEPARATE_PATH))
            {
                if ( EditorUtility.DisplayDialog("Asset Separate", $"{SEPARATE_PATH} 目录已存在，是否删除后重新执行？", "删除", "取消"))
                {
                    FileUtil.DeleteFileOrDirectory(SEPARATE_PATH);
                    FileUtil.DeleteFileOrDirectory($"{SEPARATE_PATH}.meta");
                }
                else
                {
                    return;
                }
            }

            // 记录开始时间
            var startTime = DateTime.Now;

            _fileContentDict.Clear();
            _matchingGUIDAssetPaths.Clear();

            for (var i = 0; i < paths.Count; i++)
            {
                if (!paths[i].StartsWith("Assets/"))
                    continue;

                var dependencies = AssetDatabase.GetDependencies(paths[i]);
                for (var j = 0; j < dependencies.Length; j++)
                {
                    var depend = dependencies[j];

                    var extension = Path.GetExtension(depend);
                    if (depend.StartsWith("Assets/") && !extension.Equals(".cs", StringComparison.OrdinalIgnoreCase) && !extension.Equals(".shader", StringComparison.OrdinalIgnoreCase))
                        CopyAsset(depend);

                    var progress = (i * dependencies.Length + j + 1.0f) / (paths.Count * dependencies.Length);
                    if (EditorUtility.DisplayCancelableProgressBar("复制文件...", depend, progress))
                    {
                        complete = false;
                        break;
                    }
                }

                if (complete == false)
                {
                    EditorUtility.ClearProgressBar();
                    break;
                }
            }

            // 中断流程
            if (complete == false)
                return;

            var separatePaths = GetDirectoryAllFile(SEPARATE_PATH);
            foreach (var path in separatePaths)
            {
                if (!_fileContentDict.ContainsKey(path))
                    _fileContentDict.Add(path, File.ReadAllText(path));
            }

            for (var i = 0; i < paths.Count; i++)
            {
                if (!paths[i].StartsWith("Assets/"))
                    continue;

                var dependencies = AssetDatabase.GetDependencies(paths[i]);
                for (var j = 0; j < dependencies.Length; j++)
                {
                    var dependPath = dependencies[j];
                    var extension = Path.GetExtension(dependPath);
                    if (!dependPath.StartsWith("Assets/") || extension.Equals(".cs", StringComparison.OrdinalIgnoreCase) || extension.Equals(".shader", StringComparison.OrdinalIgnoreCase))
                        continue;

                    // 移除开头的"Assets/" 然后添加"Assets/Copy_"前缀
                    var relativePath = dependPath.Substring("Assets/".Length);
                    var copyDependPath = $"{SEPARATE_PATH}/{relativePath}";

                    var depend = AssetDatabase.LoadAssetAtPath<Object>(dependPath);
                    var copyDepend = AssetDatabase.LoadAssetAtPath<Object>(copyDependPath);

                    FindAssetsContainingGUID(depend);

                    AssetDatabase.TryGetGUIDAndLocalFileIdentifier(depend, out var oGUID, out long _);
                    AssetDatabase.TryGetGUIDAndLocalFileIdentifier(copyDepend, out var nGUID, out long _);

                    foreach (var path in _matchingGUIDAssetPaths)
                    {
                        if (Regex.IsMatch(_fileContentDict[path], oGUID))
                        {
                            _fileContentDict[path] = _fileContentDict[path].Replace(oGUID, nGUID);
                            File.WriteAllText(path, _fileContentDict[path]);
                        }
                    }

                    var progress = (i * dependencies.Length + j + 1.0f) / (paths.Count * dependencies.Length);
                    if (EditorUtility.DisplayCancelableProgressBar("重建引用...", dependPath, progress))
                    {
                        complete = false;
                        break;
                    }
                }

                if (complete == false)
                {
                    EditorUtility.ClearProgressBar();
                    AssetDatabase.Refresh();
                    break;
                }
            }

            EditorUtility.ClearProgressBar();

            var endTime = DateTime.Now;
            Debug.Log($"运行时间：{(endTime - startTime).TotalSeconds:F2}秒");

            // 完整执行则显示对话框
            if (complete)
            {
                AssetDatabase.Refresh();
                EditorUtility.DisplayDialog("Asset Separate", "资产分离完成！", "确认");
            }
        }

        /// <summary> 拷贝资产 </summary>
        static void CopyAsset(string path)
        {
            // path 路径

            // 移除开头的"Assets/" 然后添加"Assets/Copy_"前缀
            var relativePath = path.Substring("Assets/".Length);
            var copyDependPath = $"{SEPARATE_PATH}/{relativePath}";

            // 确保目标文件夹存在
            var newDir = Path.GetDirectoryName(copyDependPath);
            if (!string.IsNullOrEmpty(newDir) && !Directory.Exists(newDir))
                Directory.CreateDirectory(newDir);

            // 复制资产
            if (!File.Exists(copyDependPath))
                AssetDatabase.CopyAsset(path, copyDependPath);
        }

        /// <summary> 搜索包含GUID </summary>
        static void FindAssetsContainingGUID(Object obj)
        {
            // 检查的 object

            _matchingGUIDAssetPaths.Clear();
            AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var oldGuid, out long _);

            foreach (var item in _fileContentDict)
            {
                if (Regex.IsMatch(item.Value, oldGuid))
                    _matchingGUIDAssetPaths.Add(item.Key);
            }
        }

        /// <summary> 获取文件夹所有文件 </summary>
        static string[] GetDirectoryAllFile(string path)
        {
            // path     搜索路径
            // return   返回所有文件

            var tempPath = new List<string>();

            GetAllPath(path, tempPath);

            return tempPath.Select(item => item.Replace("\\", "/")).ToArray();

            static void GetAllPath(string path, List<string> allPath)
            {
                var dirs = Directory.GetDirectories(path);

                // 对每个目录执行相同的操作
                foreach (var dir in dirs)
                    GetAllPath(dir, allPath);

                var files = Directory.GetFiles(path);
                allPath.AddRange(files);
            }
        }
    }
}